/* 
 * File:   XbeeContainer.cpp
 * Author: minaev
 * 
 * Created on 17 Ноябрь 2013 г., 12:07
 */

#include "XbeeContainer.h"
#include "Xpack.h"

/**
 * fill share memory. Adding share lines
 */
XbeeContainer::XbeeContainer(XshareMem* shmem, XUDPShareMem* udpmem, XbeeIf* xbeeif) {
    static uint32_t buf = 0;
    this->shmem = shmem;
    this->udpmem = udpmem;
    this->xbeeif = xbeeif;
    
    this->lenBlocks = new uint8_t[SLN_COUNT];

    this->lenBlocks[SLN_XCOUNT] = 2;
    this->lenBlocks[SLN_XADRS] = 4;
    this->lenBlocks[SLN_XSTAT] = 1;
    this->lenBlocks[SLN_XREQSTAT] = 1;
    this->lenBlocks[SLN_XADC] = 2;
    this->lenBlocks[SLN_XFIXADC] = 2;
    this->lenBlocks[SLN_XPINGS] = 1;
    this->lenBlocks[SLN_XBTNS] = 1;
    this->lenBlocks[SLN_XBTNOLDS] = 1;
    this->lenBlocks[SLN_XOLODEV] = 4;
    this->lenBlocks[SLN_XLOGNUM] = 2;


    for (int i = 0; i < SLN_COUNT; i++) {
        this->shmem->addLine(lenBlocks[i]);
    }

    this->shmem->addLineBlock(&(buf = 0), SLN_XCOUNT);

    //this->sleepPack = new Xpack();

    this->noSleepMode = new Xpack();
    noSleepMode->packAsRemoteATcmd(0x00000000, "SM", &(buf = 0), 1);

    //setting scan mode
    this->analogPin = new Xpack();
    analogPin->packAsRemoteATcmd(0x00000000, "D0", &(buf = 2), 1);
    this->digInPin = new Xpack();
    digInPin->packAsRemoteATcmd(0x00000000, "D1", &(buf = 3), 1);
    this->digOutOffPin = new Xpack();
    digOutOffPin->packAsRemoteATcmd(0x00000000, "D2", &(buf = 4), 1);
    this->digOutOnPin = new Xpack();
    digOutOnPin->packAsRemoteATcmd(0x00000000, "D2", &(buf = 5), 1);
    this->changeDetectMode = new Xpack();
    changeDetectMode->packAsRemoteATcmd(0x00000000, "IC", &(buf = 0x02), 1);
    
    this->unscanAnalogSample = new Xpack();
    unscanAnalogSample->packAsRemoteATcmd(0x00000000, "IR", &(buf = 0000), 2); //0x0000 - 0sec

    //setting sleep
    this->sleepModePack = new Xpack();
    sleepModePack->packAsRemoteATcmd(0x00000000, "SM", &(buf = 4), 1);
    this->sleepPeriodPack = new Xpack();
    sleepPeriodPack->packAsRemoteATcmd(0x00000000, "SP", &(buf = 0xf401), 2); //0x1f4 - 5sec
    this->awakePeriodPack = new Xpack();
    awakePeriodPack->packAsRemoteATcmd(0x00000000, "ST", &(buf = 0x4000), 2); //0x40 - 64ms
    this->applyChangesPack = new Xpack;
    applyChangesPack->packAsRemoteATcmd(0x00000000, "AC", NULL, 0);
    this->writeChangesPack = new Xpack;
    writeChangesPack->packAsRemoteATcmd(0x00000000, "WR", NULL, 0);

    this->pullupOffPack = new Xpack();
    pullupOffPack->packAsRemoteATcmd(0x00000000, "PR", &(buf = 0), 1);

    int setInd = 0;
    this->settingPacks = new Xpack*[this->countsetting];
    //this->settingPacks[setInd++] = this->noSleepMode;
    this->settingPacks[setInd++] = this->analogPin;
    this->settingPacks[setInd++] = this->digInPin;
    this->settingPacks[setInd++] = this->digOutOffPin;
    this->settingPacks[setInd++] = this->pullupOffPack;
    this->settingPacks[setInd++] = this->unscanAnalogSample;
    this->settingPacks[setInd++] = this->sleepPeriodPack;
    this->settingPacks[setInd++] = this->awakePeriodPack;
    //this->settingPacks[setInd++] = this->writeChangesPack;
    this->settingPacks[setInd++] = this->sleepModePack;
    this->settingPacks[setInd++] = this->changeDetectMode;
    this->settingPacks[setInd++] = this->applyChangesPack;


    this->scanAnalogSample = new Xpack();
    scanAnalogSample->packAsRemoteATcmd(0x00000000, "IR", &(buf = 8813), 2); //0x1388 - 5sec

    this->pingPack = new Xpack();
    pingPack->packAsRemoteATcmd(0x0000ffff, "SL", &(buf = 0), 0);


}

XbeeContainer::~XbeeContainer() {
}

/**
 * Add xbee device into system
 * @param id - device id
 * @return number added device in container or -1 if error
 */
int XbeeContainer::addXbee(uint32_t id) {
    static int res;
    static uint32_t buf = 0;
    res = -1;
    pthread_mutex_lock(&this->acsMem);

    this->shmem->addLineBlock(&id, SLN_XADRS);
    this->shmem->addLineBlock(&(buf = STAT_POWEROFF), SLN_XSTAT);
    this->shmem->addLineBlock(&(buf = STAT_POWEROFF), SLN_XREQSTAT);
    this->shmem->addLineBlock(&(buf = 0), SLN_XADC);
    this->shmem->addLineBlock(&(buf = 0), SLN_XFIXADC);
    this->shmem->addLineBlock(&(buf = 0), SLN_XPINGS);
    this->shmem->addLineBlock(&(buf = 0), SLN_XBTNS);
    this->shmem->addLineBlock(&(buf = 0), SLN_XBTNOLDS);
    this->shmem->addLineBlock(&(buf = 0), SLN_XLOGNUM);

    //    Xmsg::printf("Line len %i\n", this->shmem->getLineLength(SLN_XADRS));
    if (this->shmem->getLineLength(SLN_XCOUNT) != 0) {
        buf = this->shmem->getLineLength(SLN_XADRS);


        this->shmem->write(&(buf = this->shmem->getLineLength(SLN_XADRS)), SLN_XCOUNT, 0);
    } else {
        this->shmem->addLineBlock(&(buf = this->shmem->getLineLength(SLN_XADRS)), SLN_XCOUNT);
    }

    this->initXbee(id);

    res = this->length() - 1;

    pthread_mutex_unlock(&this->acsMem);



    return res;
}

void XbeeContainer::initXbee(uint32_t id) {
    for (int i = 0; i < countsetting; i++) {
        settingPacks[i]->setAddrRemoteATcmd(id);
        xbeeif->write(settingPacks[i]);
        usleep(100000);
    }
}

uint16_t XbeeContainer::length() {
    return this->shmem->getLineLength(SLN_XADRS);
}

/**
 * Set Xbee device parameter
 * @param numXbee - number of container
 * @param numParam - number param (ex. SLN_ADRS, SLN_XADC)
 * @param value - point to setting value
 * @return 0 - success, 1 - bad numXbee, 2 - bad numParam
 */
int XbeeContainer::setParam(uint16_t numXbee, uint8_t numParam, void* value) {
    if (numXbee >= this->length()) {
        return 1;
    }
    if (numParam >= SLN_COUNT) {
        return 2;
    }
    pthread_mutex_lock(&this->acsMem);
    shmem->write(value, numParam, numXbee);
    pthread_mutex_unlock(&this->acsMem);
    return 0;
}

/**
 * Get point to Xbee device parameter
 * @param numXbee - number device in Container
 * @param numParam - number param (ex. SLN_ADRS, SLN_XADC)
 * @return pointer to value param or NULL if error
 */
void* XbeeContainer::getParam(uint16_t numXbee, uint8_t numParam) {
    if (numXbee >= this->length()) {
        return NULL;
    }
    if (numParam >= SLN_COUNT) {
        return NULL;
    }
    static void* buf;

    pthread_mutex_lock(&this->acsMem);
    buf = shmem->read(numParam, numXbee);
    pthread_mutex_unlock(&this->acsMem);

    return buf;
}

/**
 * Set Xbee device parameter by id
 * @param idXbee - ID Xbee device
 * @param numParam - number param (ex. SLN_ADRS, SLN_XADC)
 * @param value - point to setting value
 * @return 0 - success, 1 - bad idXbee, 2 - bad numParam
 */
int XbeeContainer::setParamById(uint32_t idXbee, uint8_t numParam, void* value) {
    static int numXbee;
    pthread_mutex_lock(&this->acsMem);

    numXbee = shmem->findInLine(&idXbee, SLN_XADRS);

    pthread_mutex_unlock(&this->acsMem);

    if (numXbee == -1) {
        return 1;
    }
    return this->setParam(numXbee, numParam, value);
}

/**
 * Get point to Xbee device parameter by id
 * @param numXbee - ID Xbee device
 * @param numParam - number param (ex. SLN_ADRS, SLN_XADC)
 * @return pointer to value param or NULL if error
 */
void* XbeeContainer::getParamById(uint32_t idXbee, uint8_t numParam) {
    static int numXbee;
    pthread_mutex_lock(&this->acsMem);

    numXbee = shmem->findInLine(&idXbee, SLN_XADRS);

    pthread_mutex_unlock(&this->acsMem);

    if (numXbee == -1) {
        return NULL;
    }

    return this->getParam(numXbee, numParam);
}

void XbeeContainer::stopScan(uint16_t numXbee) {
    unscanAnalogSample->setAddrRemoteATcmd(*(uint32_t*) getParam(numXbee, SLN_XADRS));
    xbeeif->write(unscanAnalogSample);
}

void XbeeContainer::startScan(uint16_t numXbee) {
    scanAnalogSample->setAddrRemoteATcmd(*(uint32_t*) getParam(numXbee, SLN_XADRS));
    xbeeif->write(scanAnalogSample);
}

void XbeeContainer::pinAlarmOn(uint16_t numXbee) {
    digOutOnPin->setAddrRemoteATcmd(*(uint32_t*) getParam(numXbee, SLN_XADRS));
    xbeeif->write(digOutOnPin);
}

void XbeeContainer::pinAlarmOff(uint16_t numXbee) {
    digOutOffPin->setAddrRemoteATcmd(*(uint32_t*) getParam(numXbee, SLN_XADRS));
    xbeeif->write(digOutOffPin);
}

/**
 * Get pos Xbee device by Id
 * @param id - id Xbee device
 * @return position xbee device, or -1 if not found
 */
int XbeeContainer::findById(uint32_t id) {
    return shmem->findInLine(&id, SLN_XADRS);
}

bool XbeeContainer::isAlarm(uint16_t numXbee) {
    static long res;
    static uint8_t* pfixadc;
    static uint8_t* padc;
    pfixadc = (uint8_t*) getParam(numXbee, SLN_XADC);
    padc = (uint8_t*) getParam(numXbee, SLN_XFIXADC);
    res = (((*padc) << 8) | (*(padc + 1)))
            - (((*pfixadc) << 8) | (*(pfixadc + 1)));
    return (res > ALARM_DIFF) || (res < (-ALARM_DIFF));
}

void XbeeContainer::sendAlarmMessage(uint16_t numXbee) {
    //static uint8_t stat = STAT_ALARM;
    //this->setParam(numXbee,SLN_XSTAT,&stat);
    if (this->udpmem->sendPack(0xffffffff, UC_READ | 1, SLN_XSTAT, numXbee, 1) != 0) {
        Xmsg::printf("Error in send UDP alarm packet!\n");
    }
}

void XbeeContainer::sendStatusMessage(uint16_t numXbee) {
    if (this->udpmem->sendPack(0xffffffff, UC_READ | 1, SLN_XSTAT, numXbee, 1) != 0) {
        Xmsg::printf("Error in send UDP status message!\n");
    }
}

void XbeeContainer::sendBtnStatusMessage(uint16_t numXbee) {
    if (this->udpmem->sendPack(0xffffffff, UC_READ | 1, SLN_XBTNS, numXbee, 1) != 0) {
        Xmsg::printf("Error in send UDP btn status message!\n");
    }
}

void XbeeContainer::toNewStatus(uint16_t numXbee) {
    static uint8_t* pcurStatus;
    static uint8_t* pnewStatus;
    static uint8_t curStatus;
    static uint8_t newStatus;
    static uint32_t buf;
    pcurStatus = (uint8_t*)this->getParam(numXbee, SLN_XSTAT);
    pnewStatus = (uint8_t*)this->getParam(numXbee, SLN_XREQSTAT);
    if (pcurStatus != NULL && pnewStatus != NULL) {
        curStatus = *pcurStatus;
        newStatus = *pnewStatus;
        if (curStatus != newStatus) {

            switch (curStatus) {
                case STAT_ALARM:
                {
                    this->pinAlarmOff(numXbee);
                    break;
                }
            }

            switch (newStatus) {
                case STAT_POWEROFF:
                {
                    Xmsg::printf("STATUS %i: to poweroff\n", numXbee);
                    if (curStatus == STAT_SCAN ||
                            curStatus == STAT_ALARM) {
                        this->stopScan(numXbee);
                    }
                    this->setParam(numXbee, SLN_XSTAT, &newStatus);
                    this->sendStatusMessage(numXbee);
                    break;
                }
                case STAT_IDLE:
                {
                    Xmsg::printf("STATUS %i: to idle\n", numXbee);
                    if (curStatus == STAT_SCAN ||
                            curStatus == STAT_ALARM) {
                        this->stopScan(numXbee);
                    }
                    if (curStatus == STAT_POWEROFF) {

                        this->initXbee(*(uint32_t*)this->getParam(numXbee, SLN_XADRS));
                    }
                    this->setParam(numXbee, SLN_XSTAT, &newStatus);
                    this->sendStatusMessage(numXbee);
                    break;
                }
                case STAT_SCAN:
                {
                    Xmsg::printf("STATUS %i: to scan\n", numXbee);
                    if (curStatus == STAT_POWEROFF ||
                            curStatus == STAT_IDLE) {
                        this->startScan(numXbee);
                    }
                    this->setParam(numXbee, SLN_XFIXADC, &(buf = 0));
                    this->setParam(numXbee, SLN_XSTAT, &newStatus);
                    this->sendStatusMessage(numXbee);
                    break;
                }
                case STAT_ALARM:
                {
                    Xmsg::printf("STATUS %i: to alarm\n", numXbee);
                    this->pinAlarmOn(numXbee);
                    this->setParam(numXbee, SLN_XSTAT, &newStatus);
                    this->sendStatusMessage(numXbee);
                    break;
                }
            }
        }
    }
}

void XbeeContainer::pingBroadcast() {
    this->xbeeif->write(this->pingPack);
}

XshareMem* XbeeContainer::getShareMem() {
    return this->shmem;
}

XUDPShareMem* XbeeContainer::getUDPShareMem() {
    return this->udpmem;
}

